package com.example.sens.service.impl;

import com.example.sens.service.IStorageService;
import com.example.sens.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Date;
import java.util.stream.Stream;

@Service
public class StorageServiceImpl implements IStorageService {

    private final Path rootLocation;

    private final String basePath;

    @Autowired
    public StorageServiceImpl() {
        this.rootLocation = Paths.get("upload-dir");
        this.basePath = "upload-dir";
    }

    @Override
    public String distributePath(String keyPath) {
        // 根据不同文件文件类型-不同日期生成不同文件夹
        Date date = new Date();
        String datePath = DateUtils.DateFormatToString(date, "yyyy") + File.separator +
                DateUtils.DateFormatToString(date, "MM") + File.separator +
                DateUtils.DateFormatToString(date, "dd");
        Path path;
        try {
            path = Paths.get(this.basePath, keyPath, datePath);
            Files.createDirectories(path);
        } catch (IOException e) {
            throw new Error("Failed to store file path", e);
        }
        return path.toString() + File.separator;
    }

    @Override
    public String distributeJPGPath() {
        return distributePath("images");
    }

    @Override
    public String store(MultipartFile file) {
        String filename = StringUtils.cleanPath(file.getOriginalFilename());
        try {
            if (file.isEmpty()) {
                throw new Error("Failed to store empty file " + filename);
            }
            if (filename.contains("..")) {
                // This is a security check
                throw new Error(
                        "Cannot store file with relative path outside current directory "
                                + filename);
            }
            // 根据不同文件文件类型-不同日期生成不同文件夹
            Date date = new Date();
            String datePath = DateUtils.DateFormatToString(date, "yyyy") + File.separator +
                    DateUtils.DateFormatToString(date, "MM") + File.separator +
                    DateUtils.DateFormatToString(date, "dd");

            String timeStamp = String.valueOf(new Date().getTime());
            filename = timeStamp + filename.substring(filename.lastIndexOf("."), filename.length());

            Path path;
            if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") || filename.endsWith(".png")) {
                // images
                path = Paths.get(this.basePath, "images", datePath);
            } else {
                path = Paths.get(this.basePath, "other", datePath);
            }
            Files.createDirectories(path);
            Files.copy(file.getInputStream(), path.resolve(filename),
                    StandardCopyOption.REPLACE_EXISTING);
            return path.toString() + File.separator + filename;
        } catch (IOException e) {
            throw new Error("Failed to store file " + filename, e);
        }
    }

    @Override
    public Stream<Path> loadAll() {
        try {
            return Files.walk(this.rootLocation, 1)
                    .filter(path -> !path.equals(this.rootLocation))
                    .map(path -> this.rootLocation.relativize(path));
        } catch (IOException e) {
            throw new Error("Failed to read stored files", e);
        }

    }

    @Override
    public Path load(String filename) {
        if (filename.startsWith(this.basePath)) {
            filename = filename.replace(this.basePath + File.separator, "");
        }
        return rootLocation.resolve(filename);
    }

    @Override
    public Resource loadAsResource(String filename) {
        try {
            Path file = load(filename);
            Resource resource = new UrlResource(file.toUri());
            if (resource.exists() || resource.isReadable()) {
                return resource;
            } else {
                throw new Error(
                        "Could not read file: " + filename);

            }
        } catch (MalformedURLException e) {
            throw new Error("Could not read file: " + filename, e);
        }
    }

    @Override
    public void deleteAll() {
        FileSystemUtils.deleteRecursively(rootLocation.toFile());
    }

    @Override
    public void init() {
        try {
            Files.createDirectories(rootLocation);
        } catch (IOException e) {
            throw new Error("Could not initialize storage", e);
        }
    }
}
